home *** CD-ROM | disk | FTP | other *** search
Wrap
/* graphics libraries: Spline generation routines by Cary Clark, Georgiann Delaney, Michael Fairman, Pablo Fernicola, Dave Good, Robert Johnson, Keith McGreggor, Oliver Steele, David Van Brink, Chris Yerga Copyright 1987 - 1993 Apple Computer, Inc. All rights reserved. */ #include <Memory.h> #include "graphics libraries.h" enum { onCurvePoint, offCurvePoint }; typedef struct { long count; unsigned long mask; long control; long *bits; gxPoint *points; } splineBuild; static void BeginSplineBuild(splineBuild *build, long *bits, gxPoint *points) { build->count = 0; build->mask = 0; build->control = 0; build->bits = bits; build->points = points; } static void EndSplineBuild(splineBuild *build) { if (build->mask) *build->bits = build->control; } static void AddPoint(splineBuild *build, gxPoint *add, boolean offCurve) { *build->points++ = *add; if (build->mask == 0) build->mask = (-1UL >> 1) + 1; if (offCurve) build->control |= build->mask; if ((build->mask >>= 1) == 0) { *build->bits++ = build->control; build->control = 0; } ++build->count; } static void AddTangent(splineBuild *build, gxPoint *base, gxPoint *tangent, Fixed factor) { gxPoint control; control.x = base->x + FractMultiply(tangent->x, factor); control.y = base->y + FractMultiply(tangent->y, factor); AddPoint(build, &control, offCurvePoint); } gxShape MirrorSpline(long count, gxPoint *points, fract slack, boolean closed) { gxShape spline; gxPoint *mine, *next; Fixed prevLen, nextLen; gxPoint prevDir, nextDir; splineBuild build; long actIndex, estCount = 3 * count, estIndex = 2 + (estCount + 31 >> 5); long *storage = (long *)NewPtr(estIndex * sizeof(long) + estCount * sizeof(gxPoint)); BeginSplineBuild(&build, storage + 2, (gxPoint *)(storage + estIndex)); mine = next = points; if (closed) mine += count - 1; nextDir.x = next->x - mine->x; nextDir.y = next->y - mine->y; nextLen = Magnitude(nextDir.x, nextDir.y); if (nextLen) { nextDir.x = FractDivide(nextDir.x, nextLen); nextDir.y = FractDivide(nextDir.y, nextLen); } while (count--) { mine = next; if (count) ++next; else if (closed) next = points; prevLen = nextLen; if (prevLen) prevDir = nextDir; nextDir.x = next->x - mine->x; nextDir.y = next->y - mine->y; nextLen = Magnitude(nextDir.x, nextDir.y); if (nextLen) { nextDir.x = FractDivide(nextDir.x, nextLen); nextDir.y = FractDivide(nextDir.y, nextLen); if (prevLen && slack) { gxPoint tangent; tangent.x = (prevDir.x >> 1) + (nextDir.x >> 1) >> 1; tangent.y = (prevDir.y >> 1) + (nextDir.y >> 1) >> 1; AddTangent(&build, mine, &tangent, -FractMultiply(slack, prevLen)); if (nextLen != prevLen) AddPoint(&build, mine, onCurvePoint); AddTangent(&build, mine, &tangent, FractMultiply(slack, nextLen)); } else goto addThis; } else if (!closed && count == 0) addThis: AddPoint(&build, mine, onCurvePoint); } EndSplineBuild(&build); actIndex = 2 + (build.count + 31 >> 5); if (actIndex < estIndex) BlockMove(storage + estIndex, storage + actIndex, build.count * sizeof(gxPoint)); storage[0] = 1; storage[1] = build.count; spline = GXNewPaths((gxPaths *)storage); if (closed) GXSetShapeFill(spline, gxClosedFrameFill); else GXSetShapeFill(spline, gxOpenFrameFill); DisposePtr((Ptr)storage); return spline; }